{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 代码运行结果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img style=\"float: center;\" src=\"./img/log1.png\" width=\"80%\">\n",
    "\n",
    "#### 该图为每训练100次，输出训练集上的交叉熵损失和验证集上的准确率，总共训练了1000次。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img style=\"float: center;\" src=\"./img/log2.png\" width=\"60%\">\n",
    "\n",
    "#### 该图为载入训练1000次的模型对测试集进行预测的可视化结果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模型结构的理解"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "该模型是一个3层的神经网络，包含一个输入层，一个输出层和一个隐藏层。\n",
    "* 输入层：输入层有784个节点，在输入层不会进行任何计算操作，只是将输入的东西做一个输入取值；\n",
    "* 隐藏层：隐藏层有100个节点，隐藏层的节点值取决于输入层所输出的数据和输入层上每一个节点的权重(总共有784*100个权重，偏置项100个)，一般会在隐藏层对输入层输出的数据进行处理和相关计算，并通过一个激活函数(参考代码用的Relu激活函数)激活，将最终获得的数据输出；\n",
    "* 输出层：输出层有10个节点，从隐藏层接收输入，并执行隐藏层的计算，对应权重有100*10个，偏置项有10个，计算后通过softmax操作即能输出概率分布。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模型训练过程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "模型的一次训练包括前向传播和反向传播，前向传播通过权重与输入数值相乘累加，并通过激活函数得到输出值作为下一层的输入值，逐层计算得到最终的输出值。然后进行反向传播，通过比较输出y和真值t，对参与计算的w进行调整，其计算方法是从网络的输出层开始，向输入层方向逐层计算梯度并更新权重，与前向传播正好相反。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 计算图的理解"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img style=\"float: center;\" src=\"./img/graph.png\" width=\"100%\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上图为训练识别mnist手写数字的模型的数据流图，主要由四个部分构成:<br>\n",
    "1、张量（Tensor）<br>\n",
    "2、操作（Option）<br>\n",
    "3、变量（Variable）<br>\n",
    "4、会话（Session）<br>\n",
    "\n",
    ">在计算图计算或者张量的运算中，会经常使用一些方法来对数据进行操作,包括最简单的对元素的运算，对矩阵进行运算，定义常量，大量的神经元函数的操作以及保存模型的相关操作等。上图中包含的操作有placehold、Matmul、add、Relu、Softmax、ArgMax、Equal、Cast、Mean、Saver和Restore等。\n",
    "\n",
    ">变量就是在计算图的过程中可以改变的节点，在本例中，权重w和偏置项b都会随着迭代的进行而不断变化着，这样的值就可以拿来作为变量。在实际的训练过程中，一般会把需要训练的值设置为变量。一般来讲，在使用变量的时候，我们都会给变量设置一个初始值，然后根据训练的次数迭代，再将真正的变量不断地推断出来。一般会通过构造一个Variable类的实例在图中添加一个变量。当这个变量被设置初始值后，这个变量的形状和类型就会被固定下来。通过assign()函数来改变它，通过Variable()创造的变量可以作为图中的其他操作来使用，你也可以在图中添加节点，对变量进行算术操作。\n",
    "\n",
    ">在Tensorflow中，启动一个图的前提是先要创建一个会话（Session）,Tensorflow的所有对图的操作，都必须放在会话中进行。在会话中提供了一个run方法，用来执行计算图的整体或局部的操作。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 解释这里模型效果为何比较差"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里的神经网络模型只有一个隐藏层，神经元数目也较少，模型相对比较简单，而且训练轮次较少，所以模型效果比较差。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
